#include "qcurvetool.h"
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSceneContextMenuEvent>
#include <QImage>
#include <QPainter>


QCurveTool::QCurveTool(QObject *parent)
    :QMyTool(parent),operating(0),currentPath(0),Points(),ControlPoints(),ControlLines()
{
    isAddingPoint=false;
    isMovingPoint=false;
    isMovingCPoint=false;
    point1=QPointF();
    point2=QPointF();
}
QCurveTool::~QCurveTool()
{

}
void QCurveTool::Finalize()
{
	if(operating)
	{
		if(Points.size()<1)
		{
			Container->removeItem(operating);
			delete operating;
			if(Container->isEntered())
			{
				Container->Leave();
				controller->receiveMessage(new SelectContainerMessage());
			}
			controller->receiveMessage(new DeleteNodeMessage(controller->NumberOfObjects()-1));
		}
		else
		{
			if(Container->isEntered())
			{
				Container->removeItem(operating);
				delete operating;
				Container->Leave();
				controller->receiveMessage(new SelectContainerMessage());						
				int i=controller->NumberOfObjects()-1;


				Container->AddPixmapItem(i);


				operating=0;
				currentPath=0;
				Points.clear();
				ControlPoints.clear();
				ControlLines.clear();
			}
			else
			{
				if(!(Container->IsItemExist(operating)))
					Container->AddItemLink(operating,controller->NumberOfObjects()-1);
				//operating->setFlag(QGraphicsItem::ItemIsMovable, true);
				operating->setFlag(QGraphicsItem::ItemIsSelectable, true);
				operating->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
				operating=0;
				currentPath=0;
				for(int i=0;i!=Points.size();++i)
				{
					Container->removeItem(Points[i]);
					delete Points[i];
				}
				Points.clear();
				for(int i=0;i!=ControlPoints.size();++i)
				{
					if(ControlPoints[i])
					{
						Container->removeItem(ControlPoints[i]);
						delete ControlPoints[i];
					}
				}
				ControlPoints.clear();
				for(int i=0;i!=ControlLines.size();++i)
				{
					if(ControlLines[i])
					{
						Container->removeItem(ControlLines[i]);
						delete ControlLines[i];
					}
				}
				ControlLines.clear();
			}
		}
		controller->receiveMessage(new CancleCurrentEditObjectsMessage());
	}
}
void QCurveTool::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * mouseEvent)
{
}

void QCurveTool::mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent)
{
    if(Container->mouseGrabberItem())
    {
        if(Container->mouseGrabberItem()->type()==QGraphicsPathItem::Type)
        {
			controller->receiveMessage(new CancleCurrentEditObjectsMessage());
            if(operating)//!=Container->mouseGrabberItem())
            {
                if(Points.size()<1)
                {
                    Container->removeItem(operating);
                    delete operating;
					if(Container->isEntered())
					{
						Container->Leave();
						controller->receiveMessage(new SelectContainerMessage());
					}
					controller->receiveMessage(new DeleteNodeMessage(controller->NumberOfObjects()-1));
                }
                else
                {
					if(Container->isEntered())
					{
						Container->removeItem(operating);
						delete operating;
						Container->Leave();
						controller->receiveMessage(new SelectContainerMessage());	


						int i=controller->NumberOfObjects()-1;
						Container->AddPixmapItem(i);


						currentPath=0;
						Points.clear();
						ControlPoints.clear();
						ControlLines.clear();
					}
					else
					{
						if(!(Container->IsItemExist(operating)))
							Container->AddItemLink(operating,controller->NumberOfObjects()-1);
						//operating->setFlag(QGraphicsItem::ItemIsMovable, true);
						operating->setFlag(QGraphicsItem::ItemIsSelectable, true);
						operating->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
						currentPath=0;
						for(int i=0;i!=Points.size();++i)
						{
						    Container->removeItem(Points[i]);
						    delete Points[i];
						}
						Points.clear();
						for(int i=0;i!=ControlPoints.size();++i)
						{
							if(ControlPoints[i])
							{
								Container->removeItem(ControlPoints[i]);
								delete ControlPoints[i];
							}
						}
						ControlPoints.clear();
						for(int i=0;i!=ControlLines.size();++i)
						{
							if(ControlLines[i])
							{
								Container->removeItem(ControlLines[i]);
								delete ControlLines[i];
							}
						}
						ControlLines.clear();
					}
                }
            }
            operating=(QGraphicsPathItem*)(Container->mouseGrabberItem());
            QPainterPath src=operating->path();
            for(int i=0;i!=src.elementCount();++i)
            {
                if(src.elementAt(i).type==QPainterPath::CurveToElement)
                {
                    Points.push_back(new QGraphicsRectItem(-5,-5,10,10,operating,Container) );
                    Points.last()->setFlag(QGraphicsItem::ItemIsMovable, true);
                    Points.last()->setFlag(QGraphicsItem::ItemIsSelectable, true);
                    Points.last()->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
                    Points.last()->setPos(src.elementAt(i+2));
                    ControlPoints.push_back(new QGraphicsEllipseItem(-5,-5,10,10,operating,Container));
                    ControlPoints.last()->setFlag(QGraphicsItem::ItemIsMovable, true);
                    ControlPoints.last()->setFlag(QGraphicsItem::ItemIsSelectable, true);
                    ControlPoints.last()->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
                    ControlPoints.last()->setPos(src.elementAt(i+1));
                    ControlPoints.push_back(new QGraphicsEllipseItem(-5,-5,10,10,operating,Container));
                    ControlPoints.last()->setFlag(QGraphicsItem::ItemIsMovable, true);
                    ControlPoints.last()->setFlag(QGraphicsItem::ItemIsSelectable, true);
                    ControlPoints.last()->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
                    if(src.elementCount()<=i+3||src.elementAt(i+3).type==QPainterPath::LineToElement)
                        ControlPoints.last()->setPos(Points.last()->pos()*2-ControlPoints[ControlPoints.size()-2]->pos());
                    else
                        ControlPoints.last()->setPos(src.elementAt(i+3));

                    ControlLines.push_back(new QGraphicsLineItem(operating,Container));
                    ControlLines.last()->setLine(QLineF(ControlPoints[ControlPoints.size()-2]->pos(),ControlPoints.last()->pos()));
                }
                else if(src.elementAt(i).type==QPainterPath::LineToElement)
                {
                    Points.push_back(new QGraphicsRectItem(-5,-5,10,10,operating,Container) );
                    Points.last()->setFlag(QGraphicsItem::ItemIsMovable, true);
                    Points.last()->setFlag(QGraphicsItem::ItemIsSelectable, true);
                    Points.last()->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
                    Points.last()->setPos(src.elementAt(i));
                    ControlPoints.push_back(0);
                    ControlPoints.push_back(0);
                    ControlLines.push_back(0);
                }
                else if(src.elementAt(i).type==QPainterPath::MoveToElement)
                {
                    Points.push_back(new QGraphicsRectItem(-5,-5,10,10,operating,Container) );
                    Points.last()->setFlag(QGraphicsItem::ItemIsMovable, true);
                    Points.last()->setFlag(QGraphicsItem::ItemIsSelectable, true);
                    Points.last()->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
                    Points.last()->setPos(src.elementAt(i));
                    if(src.elementCount()<=i+1||src.elementAt(i+1).type==QPainterPath::LineToElement)
                    {
                        ControlPoints.push_back(0);
                        ControlPoints.push_back(0);
                        ControlLines.push_back(0);
                    }
                    else
                    {
                        ControlPoints.push_back(new QGraphicsEllipseItem(-5,-5,10,10,operating,Container));
                        ControlPoints.last()->setFlag(QGraphicsItem::ItemIsMovable, true);
                        ControlPoints.last()->setFlag(QGraphicsItem::ItemIsSelectable, true);
                        ControlPoints.last()->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
                        ControlPoints.last()->setPos(src.elementAt(i)*2-src.elementAt(i+1));
                        ControlPoints.push_back(new QGraphicsEllipseItem(-5,-5,10,10,operating,Container));
                        ControlPoints.last()->setFlag(QGraphicsItem::ItemIsMovable, true);
                        ControlPoints.last()->setFlag(QGraphicsItem::ItemIsSelectable, true);
                        ControlPoints.last()->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
                        ControlPoints.last()->setPos(src.elementAt(i+1));
                        ControlLines.push_back(new QGraphicsLineItem(operating,Container));
                        ControlLines.last()->setLine(QLineF(ControlPoints[ControlPoints.size()-2]->pos(),ControlPoints.last()->pos()));
                    }
                }
            }
			controller->receiveMessage(new SelectObjectsMessage(SelectObjectsArgs(Container->ItemIndex(operating))));

        }
        else
        {
            int index=Points.indexOf((QGraphicsRectItem*)(Container->mouseGrabberItem()));
            int index1=ControlPoints.indexOf((QGraphicsEllipseItem*)(Container->mouseGrabberItem()));
            if(index+1)
            {
				//operating->setFlag(QGraphicsItem::ItemIsMovable, false);
				operating->setFlag(QGraphicsItem::ItemIsSelectable, false);
				operating->setFlag(QGraphicsItem::ItemSendsGeometryChanges, false);


                isMovingPoint=true;
                point1=Points[index]->pos();
                point2=ControlPoints[index*2]?(ControlPoints[index*2]->pos()):QPointF();
                index_temp=index;
                QPainterPath path=operating->path();
                for(path_index_temp=-1;path_index_temp!=path.elementCount()&&index>=0;++path_index_temp)
                    if(path.elementAt(path_index_temp+1).type!=QPainterPath::CurveToDataElement)
                        --index;
            }
            else if(index1+1)
            {
				//operating->setFlag(QGraphicsItem::ItemIsMovable, false);
				operating->setFlag(QGraphicsItem::ItemIsSelectable, false);
				operating->setFlag(QGraphicsItem::ItemSendsGeometryChanges, false);


                isMovingCPoint=true;
                index_temp=index1;
                index1=index1/2;
                point1=Points[index1]->pos();
                QPainterPath path=operating->path();
                for(path_index_temp=-1;path_index_temp!=path.elementCount()&&index1>=0;++path_index_temp)
                    if(path.elementAt(path_index_temp+1).type!=QPainterPath::CurveToDataElement)
                        --index1;

            }
        }
    }
    else
    {
        if(mouseEvent->button()==Qt::RightButton)
        {
            if(operating)
            {
                if(Points.size()<1)
                {
                    Container->removeItem(operating);
                    delete operating;
					if(Container->isEntered())
					{
						Container->Leave();
						controller->receiveMessage(new SelectContainerMessage());
					}
					controller->receiveMessage(new DeleteNodeMessage(controller->NumberOfObjects()-1));
                }
                else
                {
					if(Container->isEntered())
					{
						Container->removeItem(operating);
						delete operating;
						Container->Leave();
						controller->receiveMessage(new SelectContainerMessage());


						int i=controller->NumberOfObjects()-1;
						Container->AddPixmapItem(i);


						operating=0;
						currentPath=0;
						Points.clear();
						ControlPoints.clear();
						ControlLines.clear();
					}
					else
					{
						if(!(Container->IsItemExist(operating)))
							Container->AddItemLink(operating,controller->NumberOfObjects()-1);
						//operating->setFlag(QGraphicsItem::ItemIsMovable, true);
						operating->setFlag(QGraphicsItem::ItemIsSelectable, true);
						operating->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
						operating=0;
						currentPath=0;
						for(int i=0;i!=Points.size();++i)
						{
							Container->removeItem(Points[i]);
							delete Points[i];
						}
						Points.clear();
						for(int i=0;i!=ControlPoints.size();++i)
						{
							if(ControlPoints[i])
							{
								Container->removeItem(ControlPoints[i]);
								delete ControlPoints[i];
							}
						}
						ControlPoints.clear();
						for(int i=0;i!=ControlLines.size();++i)
						{
							if(ControlLines[i])
							{
								Container->removeItem(ControlLines[i]);
								delete ControlLines[i];
							}
						}
						ControlLines.clear();
					}
                }
            }
        }
        else
        {
            isAddingPoint=true;
            point1=operating?(operating->mapFromScene(mouseEvent->scenePos())):(mouseEvent->scenePos());

			if(operating)
			{
				//operating->setFlag(QGraphicsItem::ItemIsMovable, false);
				operating->setFlag(QGraphicsItem::ItemIsSelectable, false);
				operating->setFlag(QGraphicsItem::ItemSendsGeometryChanges, false);
			}


            Points.push_back(new QGraphicsRectItem(-5,-5,10,10,operating,Container) );
            Points.last()->setFlag(QGraphicsItem::ItemIsMovable, true);
            Points.last()->setFlag(QGraphicsItem::ItemIsSelectable, true);
            Points.last()->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
            Points.last()->setPos(point1);
            ControlPoints.push_back(0);
            ControlPoints.push_back(0);
            ControlLines.push_back(0);
            currentPath=new QGraphicsPathItem(operating,Container);
			currentPath->setPen(Container->Pen());
			currentPath->setBrush(Container->Brush());
            if(Points.size()>1)
            {
                QPainterPath curp;
                curp.moveTo(Points[Points.size()-2]->pos());
                curp.lineTo(point1);
                currentPath->setPath(curp);
            }
        }
    }
}

void QCurveTool::mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent)
{
    if(isAddingPoint)
    {
        QPointF current=operating?(operating->mapFromScene(mouseEvent->scenePos())):(mouseEvent->scenePos());
        QPointF temp=current-point1;
        qreal x=temp.x();
        qreal y=temp.y();
        if(sqrt(x*x+y*y)>1)
        {
            if(!ControlPoints[Points.size()*2-1])
            {
                ControlPoints.pop_back();
                ControlPoints.pop_back();
                ControlPoints.push_back(new QGraphicsEllipseItem(-5,-5,10,10,operating,Container));
                ControlPoints.last()->setFlag(QGraphicsItem::ItemIsMovable, true);
                ControlPoints.last()->setFlag(QGraphicsItem::ItemIsSelectable, true);
                ControlPoints.last()->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
                ControlPoints.push_back(new QGraphicsEllipseItem(-5,-5,10,10,operating,Container));
                ControlPoints.last()->setFlag(QGraphicsItem::ItemIsMovable, true);
                ControlPoints.last()->setFlag(QGraphicsItem::ItemIsSelectable, true);
                ControlPoints.last()->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
                ControlLines.pop_back();;
                ControlLines.push_back(new QGraphicsLineItem(operating,Container));
            }
            ControlPoints.last()->setPos(current);
            ControlPoints[ControlPoints.size()-2]->setPos(point1*2-current);
            ControlLines.last()->setLine(QLineF(point1*2-current,current));
        }
        if(Points.size()>1)
        {
            if(ControlPoints.last())
            {
                QPainterPath curp;
                curp.moveTo(Points[Points.size()-2]->pos());
                curp.cubicTo((ControlPoints[ControlPoints.size()-3])
                             ?(ControlPoints[ControlPoints.size()-3]->pos())
                            :(
                                  (Points.size()>2)
                                  ?(Points[Points.size()-2]->pos()*4-Points[Points.size()-3]->pos())/3.0
                                 :(Points[Points.size()-2]->pos())
                            ),point1*2-current,point1);
                currentPath->setPath(curp);
            }
        }
    }
    else if(Container->mouseGrabberItem())
    {
        QPointF current=operating?(operating->mapFromScene(mouseEvent->scenePos())):(mouseEvent->scenePos());
        if(isMovingPoint)
        {
            QPainterPath path=operating->path();
            Points[index_temp]->setPos(current);
            if(ControlPoints[index_temp*2])
            {
                QPointF tp=point2+current-point1;
                ControlPoints[index_temp*2]->setPos(tp);
                ControlPoints[index_temp*2+1]->setPos(current*2-tp);
                ControlLines[index_temp]->setLine(QLineF(tp,current*2-tp));
				if(path.elementAt(path_index_temp).type==QPainterPath::MoveToElement)
				{
					path.setElementPositionAt(path_index_temp,current.x(),current.y());
					if(index_temp+1<Points.size()&&path.elementAt(path_index_temp+1).type==QPainterPath::CurveToElement)
					{
						tp=current*2-tp;
						path.setElementPositionAt(path_index_temp+1,tp.x(),tp.y());
					}
				}
				else
				{
					path.setElementPositionAt(path_index_temp+1,tp.x(),tp.y());
					path.setElementPositionAt(path_index_temp+2,current.x(),current.y());
					if(index_temp+1<Points.size()&&path.elementAt(path_index_temp+3).type==QPainterPath::CurveToElement)
					{
						tp=current*2-tp;
						path.setElementPositionAt(path_index_temp+3,tp.x(),tp.y());
					}
				}
            }
            else
            {
                path.setElementPositionAt(path_index_temp,current.x(),current.y());
                if(index_temp+1<Points.size()&&path.elementAt(path_index_temp+1).type==QPainterPath::CurveToElement)
                {
                    QPointF tp=path_index_temp?path.elementAt(path_index_temp-1):path.elementAt(path_index_temp);
                    tp=(current*4-tp)/3.0;
                    path.setElementPositionAt(path_index_temp+1,tp.x(),tp.y());
                }
            }
            operating->setPath(path);
        }
        else if(isMovingCPoint)
        {
            QPainterPath path=operating->path();
            int index_temp_1=index_temp%2?index_temp-1:index_temp+1;
            ControlPoints[index_temp]->setPos(current);
            ControlPoints[index_temp_1]->setPos(point1*2-current);
            ControlLines[index_temp/2]->setLine(QLineF(current,point1*2-current));
            qreal xt=index_temp<index_temp_1?current.x():point1.x()*2-current.x();
            qreal yt=index_temp<index_temp_1?current.y():point1.y()*2-current.y();
			if(path.elementAt(path_index_temp).type==QPainterPath::CurveToElement)
			{
				path.setElementPositionAt(path_index_temp+1,xt,yt);
				if(index_temp/2+1<Points.size()&&path.elementAt(path_index_temp+3).type==QPainterPath::CurveToElement)
				{
					xt=point1.x()*2-xt;
					yt=point1.y()*2-yt;
					path.setElementPositionAt(path_index_temp+3,xt,yt);
				}
			}
			else
			{
				if(index_temp/2+1<Points.size()&&path.elementAt(path_index_temp+1).type==QPainterPath::CurveToElement)
				{
					xt=point1.x()*2-xt;
					yt=point1.y()*2-yt;
					path.setElementPositionAt(path_index_temp+1,xt,yt);
				}
			}
            operating->setPath(path);
        }
    }
}
void QCurveTool::mouseReleaseEvent(QGraphicsSceneMouseEvent * mouseEvent)
{
    if(isAddingPoint)
    {
        isAddingPoint=false;
        QPainterPath path;
        if(!operating)
        {
            operating=new QGraphicsPathItem();
			Points[0]->setParentItem(operating);
			if(ControlPoints[0])
			{
				ControlPoints[0]->setParentItem(operating);
				ControlPoints[1]->setParentItem(operating);
				ControlLines[0]->setParentItem(operating);
			}
            Container->addItem(operating);
            path.moveTo(point1);
            operating->setPath(path);
			operating->setPen(Container->Pen());
			operating->setBrush(Container->Brush());


			controller->receiveMessage(new NewNodeMessage(NewNodeArgs(pathNode,QPointF(),QVector<QPointF>())));
			if(controller->GetNodeType(-1)==MovieClip)
			{
				controller->receiveMessage(new SelectContainerMessage(controller->NumberOfObjects()-1));
				Container->Enter();
				((ShapeNode*)(controller->GetObjectByIndex(0)))->LinePenRef()=Container->Pen();
				((ShapeNode*)(controller->GetObjectByIndex(0)))->FillBrushRef()=Container->Brush();
				((ShapeNode*)(controller->GetObjectByIndex(-1)))->SetDirty();
				((ShapeNode*)(controller->GetObjectByIndex(-1)))->UpdateCache();
				controller->receiveMessage(new SelectObjectsMessage(SelectObjectsArgs(0)));
			}

			else
			{
				((ShapeNode*)(controller->GetObjectByIndex(controller->NumberOfObjects()-1)))->LinePenRef()=Container->Pen();
				((ShapeNode*)(controller->GetObjectByIndex(controller->NumberOfObjects()-1)))->FillBrushRef()=Container->Brush();
				((ShapeNode*)(controller->GetObjectByIndex(-1)))->SetDirty();
				((ShapeNode*)(controller->GetObjectByIndex(-1)))->UpdateCache();
				controller->receiveMessage(new SelectObjectsMessage(SelectObjectsArgs(controller->NumberOfObjects()-1)));
			}

        }
        else
        {
            path=operating->path();
            if(ControlPoints.last())
            {
                path.cubicTo((ControlPoints[ControlPoints.size()-3])
                             ?(ControlPoints[ControlPoints.size()-3]->pos())
                            :(
                                  (Points.size()>2)
                                  ?(Points[Points.size()-2]->pos()*4-Points[Points.size()-3]->pos())/3.0
                                 :(Points[Points.size()-2]->pos())
                                   ),ControlPoints[ControlPoints.size()-2]->pos(),Points.last()->pos());
            }
            else
            {
                path.lineTo(Points.last()->pos());
            }
            operating->setPath(path);
        }
        Container->removeItem(currentPath);
        delete currentPath;
        currentPath=0;
		if(ControlPoints.last())
		{
			controller->receiveMessage(new AddPointMessage(AddPointArgs(PointType::Psymmetrical,
				Points.last()->pos(),ControlPoints[ControlPoints.size()-2]->pos())));
		}
		else
		{
			controller->receiveMessage(new AddPointMessage(AddPointArgs(PointType::Plinear,
				Points.last()->pos())));
		}
    }
    else if(isMovingPoint)
    {
        isMovingPoint=false;
		controller->receiveMessage(new MovePointMessage(MovePointArgs(curvePointType::curvePoint,
			index_temp,Points[index_temp]->pos())));
    }
    else if(isMovingCPoint)
    {
        isMovingCPoint=false;
		controller->receiveMessage(new MovePointMessage(MovePointArgs(index_temp%2?curvePointType::RcontrolPoint:curvePointType::LcontrolPoint,
			index_temp/2,ControlPoints[index_temp]->pos())));
    }
}

void QCurveTool::contextMenuEvent(QGraphicsSceneContextMenuEvent * mouseEvent)
{
}
